﻿/*
 * Rappelz: Endless Odyssey - The first free open source Rappelz server emulator
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Rappelz.GameServer
{
    public class ChannelManager
    {
        public static List<ChannelInfo> g_vChannelInfo = new List<ChannelInfo>();
        public static ChannelUseInfo[] g_vChannelUseInfo = new ChannelUseInfo[256];
        public static int[] g_channelLayerMap = new int[256];
        /// <summary>
        /// The instance!
        /// </summary>
        protected static ChannelManager m_instance;

        /// <summary>
        /// Returns the instance
        /// </summary>
        public static ChannelManager Instance
        {
            get
            {
                if (m_instance == null)
                    m_instance = new ChannelManager();
                return m_instance;
            }
        }

        public enum ChannelType : int
        {
            Nothing = 0,
            UserLimit = 1,
            Dungeon = 2,
        }

        public static void Init()
        {
            for (int i = 0; i < 256; ++i)
            {
                g_vChannelUseInfo[i] = new ChannelUseInfo();
            }
        }

        public static int GetChannelNum(byte layer)
        {
            return g_channelLayerMap[layer];
        }

        public static int GetChannelId(float x, float y)
        {
            foreach (ChannelInfo ci in g_vChannelInfo)
            {
                foreach (X2D.Boxf box in ci.regions)
                {
                    if(box.IsInclude(x,y))
                        return ci.channel_id;
                }
            }
            return 0;
        }

        public static int GetChannelId(byte layer)
        {
            return g_vChannelUseInfo[layer].channel_id;
        }
        public static void EnterPlayerToLayer(byte layer)
        {

        }

        public static void LeavePlayerFromLayer(byte layer)
        {

        }


        public static int GetPlayerCountInLayer(byte layer)
        {
            return 1;
        }

        public static byte GetProperLayer(float x, float y)
        {
//            s_csChannelLock.baseclass_0.vfptr->Lock(&s_csChannelLock);

            byte result = 0;
            int playerCnt = 2147483647;

            foreach (ChannelInfo info in g_vChannelInfo)
            {
                if (info.type == 1)
                {
                    foreach (X2D.Boxf bf in info.regions)
                    {
                        if (bf.IsInclude(x,y))
                        {
                            foreach(ChannelInfo.ChannelLayerMap clm in info.channel_layer_map)
                            {
                                if (clm.player_cnt < info.info.limit_user.max_num)
                                {
                                    return (byte)clm.layer;
                                }
                                if (clm.player_cnt < playerCnt)
                                {
                                    playerCnt = clm.player_cnt;
                                    result = (byte)clm.layer;
                                }
                            }
                        }
                    }
                }
            }
//            v14->UnLock(&s_csChannelLock);
            return result;

        }

        public static int GetProperChannel(int channel_id)
        {
            int chanNum = 0;
            int pcnt = 2147483647;

            foreach (ChannelInfo ci in g_vChannelInfo)
            {
                if (ci.channel_id == channel_id)
                {
                    if (ci.type == 1)
                    {
                        foreach (ChannelInfo.ChannelLayerMap clm in ci.channel_layer_map)
                        {
                            if (clm.player_cnt < ci.info.limit_user.proper_user)
                            {
                                return clm.channel_num;
                            }
                            if (clm.player_cnt < pcnt)
                            {
                                pcnt = clm.player_cnt;
                                chanNum = clm.channel_num;
                            }
                        }
                    }
//                    break;
                }
            }
            return chanNum;
        }

// Function       :   public static int ChannelManager::GetMinChannelNo(int)
// Function       :   public static int ChannelManager::GetMaxChannelNo(int)

        public static byte GetLayerOfChannel(int channel_id, int channel_num)
        {
            foreach (ChannelInfo info in g_vChannelInfo)
            {
                if (info.channel_id == channel_id)
                {
                    foreach (ChannelInfo.ChannelLayerMap clm in info.channel_layer_map)
                    {
                        if (clm.channel_num == channel_num)
                            return (byte)clm.layer;
                    }
                    return 0;
                }
            }
            return 0;
        }


        public static int GetChannelType(int channel_id)
        {
            foreach (ChannelInfo ci in g_vChannelInfo)
            {
                if(ci.channel_id == channel_id)
                    return ci.type;
            }
            return 0;
        }

        public static bool GetLayersOfChannel(int channel_id, ref List<byte> vLayers)
        {
            if (channel_id != 0)
            {
                foreach (ChannelInfo info in g_vChannelInfo)
                {
                    if (info.channel_id == channel_id)
                    {
                        if (info.type == 1)
                        {
                            foreach (ChannelInfo.ChannelLayerMap clm in info.channel_layer_map)
                            {
                                vLayers.Add((byte)clm.layer);
                            }
                        }
                        else
                        {
                            if (info.type == 2)
                            {
                                for(int i = 0; i < 25; ++i)
                                {
                                    vLayers.Add((byte)i);
                                }
                            }
                        }
                        break;
                    }
                }
            }
            if (vLayers.Count == 0)
                vLayers.Add(0);
            return vLayers.Count != 0;
        }
// Function       :   public static bool ChannelManager::GetRegionOfChannel(int, struct X2D::Box<float> &)

        public static void RegisterChannelInfo(int channel_id, X2D.Boxf channel_region, int channel_type)
        {
            foreach (ChannelInfo ci in g_vChannelInfo)
            {
                if(ci.channel_id == channel_id)
                {
                    ci.regions.Add(channel_region);
                    return;
                }
            }

            ChannelInfo info = new ChannelInfo();
            info.channel_id = channel_id;
            info.type = channel_type;
            info.info.limit_user.max_num = 10;
            info.regions.Add(channel_region);
            g_vChannelInfo.Add(info);
        }

        public static void RegisterUserLimitChannelInfo(int channel_id, int proper_user, int max_channel_num)
        {
            foreach (ChannelInfo ci in g_vChannelInfo)
            {
                if(ci.channel_id == channel_id)
                {
                    ci.info.limit_user.max_num = 2;// max_channel_num;
                    ci.info.limit_user.proper_user = proper_user;

                    int chan_num = 0;
                    int layer = 1;
                    do
                    {
                        if (chan_num > max_channel_num )
                            break;
                        if (g_vChannelUseInfo[layer].channel_id == 0)
                        {
                            g_vChannelUseInfo[layer].channel_id = channel_id;
                            ++chan_num;
                            g_channelLayerMap[layer] = chan_num;
                            ChannelInfo.ChannelLayerMap cm = new ChannelInfo.ChannelLayerMap();
                            cm.channel_num = chan_num;
                            cm.layer = layer;
                            cm.player_cnt = 0;
                            ci.channel_layer_map.Add(cm);
                        }
                        ++layer;
                    }
                    while (layer < 256);

                }
            }

//             int v3; // esi@5
//             signed int v4; // edi@5
//             ArMoveVector::MOVE_INFO *v5; // eax@8
//             XMemoryPool::_TAG _Val; // [sp+4h] [bp-14h]@1
//             std::_Vector_iterator<_CHANNEL_INFO,std::allocator<_CHANNEL_INFO> > it; // [sp+10h] [bp-8h]@1
// 
//             std::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>(
//                 &_Val.pPool,
//                 dword_651AD4,
//                 &g_vChannelInfo);
//             it.baseclass_0.baseclass_0.baseclass_0._Mycont = _Val.pPool;
//             it.baseclass_0._Myptr = _Val.pFirstBlock;
//             std::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>(
//                 &_Val.pPool,
//                 dword_651AD8,
//                 &g_vChannelInfo);
//             if ( !std::_Vector_const_iterator<X2D::Point<float>_std::allocator<X2D::Point<float>>>::operator__(&it, &_Val.pPool) )
//             {
//                 while ( LODWORD(std::_Vector_const_iterator<PartyManager::PartyInfo___std::allocator<PartyManager::PartyInfo__>>::operator_(&it)->end.x) != channel_id )
//                 {
//                     std::_Vector_const_iterator<GameContent::MapLocationInfo_std::allocator<GameContent::MapLocationInfo>>::operator__(&it);
//                     std::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>(
//                         &_Val.pPool,
//                         dword_651AD8,
//                         &g_vChannelInfo);
//                     if ( std::_Vector_const_iterator<X2D::Point<float>_std::allocator<X2D::Point<float>>>::operator__(
//                              &it,
//                              &_Val.pPool) )
//                         return;
//                 }
//             }
        }

    }

    public class ChannelInfo
    {
        public class ChannelLayerMap
        {
            public int channel_num;
            public int layer;
            public int player_cnt;
        }

        public class ChannelInfo2
        {
            public int proper_user;
            public int max_num;
        }

        public class ChannelInfo1
        {
            public ChannelInfo2 limit_user = new ChannelInfo2();
        }

        public int channel_id;
        public List<X2D.Boxf> regions = new List<X2D.Boxf>();
        public int type;
        public List<ChannelLayerMap> channel_layer_map = new List<ChannelLayerMap>();
        public ChannelInfo1 info = new ChannelInfo1();
    }

    public class ChannelUseInfo
    {
        public int channel_id;
        public int channel_num;
    }

}
